package com.qd.core.aspect.wx;

import com.cdqidi.util.AnnotationUtil;
import com.jfinal.springboot.weixin.annotation.ApiType;
import com.jfinal.springboot.weixin.annotation.WxApi;
import com.jfinal.weixin.sdk.api.ApiConfigKit;
import com.jfinal.wxaapp.WxaConfigKit;
import com.qd.common.sys.util.SecurityUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 记录操作日志
 *
 * @author sjk
 */
@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class WxApiAspect {
    private final HttpServletRequest request;

    /**
     * 定义切入点
     */
    @Pointcut("@annotation(com.jfinal.springboot.weixin.annotation.WxApi)")
    public void wxApiPointCut() {
    }

    @Before(value = "wxApiPointCut()")
    public void doBefore(JoinPoint joinPoint) {
        final WxApi wxApi = AnnotationUtil.getMethodAnnotation(joinPoint, WxApi.class);
        if (null == wxApi) {
            return;
        }
        final String appId = getAppId();
        if (!StringUtils.hasLength(appId)) {
            return;
        }
        if (wxApi.type().equals(ApiType.WX)) {
            ApiConfigKit.setThreadLocalAppId(appId);
        }
        if (wxApi.type().equals(ApiType.WXA)) {
            WxaConfigKit.setThreadLocalAppId(appId);
        }
    }

    /**
     * 最终结束
     */
    @After(value = "wxApiPointCut()")
    public void doAfter(JoinPoint joinPoint) {
        log.info("回收资源");
        clear(joinPoint);
    }

    protected void clear(final JoinPoint joinPoint) {
        final String appId = getAppId();
        if (!StringUtils.hasLength(appId)) {
            return;
        }
        Optional.ofNullable(AnnotationUtil.getMethodAnnotation(joinPoint, WxApi.class)).ifPresent(wxApi -> {
            if (wxApi.type().equals(ApiType.WX)) {
                ApiConfigKit.setThreadLocalAppId(appId);
            }
            if (wxApi.type().equals(ApiType.WXA)) {
                WxaConfigKit.setThreadLocalAppId(appId);
            }
        });
    }

    protected String getAppId() {
        AtomicReference<String> atomicReference = new AtomicReference<>("");
        Optional.ofNullable(SecurityUtils.getLoginUser()).flatMap(loginUser -> Optional.ofNullable(loginUser.getUser())).flatMap(dto -> Optional.ofNullable(dto.getAppUserExtend())).ifPresent(appUserExtend -> atomicReference.set(appUserExtend.getAppId()));
        String appId = atomicReference.get();
        if (StringUtils.hasLength(appId)) {
            return appId;
        }
        appId = request.getParameter("appId");
        if (StringUtils.hasLength(appId)) {
            return appId;
        }
        return request.getHeader("appId");
    }
}
